Enable mapping higher physical address
authorLin Ma <[email protected]>
Mon, 2 Jun 2014 18:45:36 +0000 (11:45 -0700)
committerLin Ma <[email protected]>
Mon, 2 Jun 2014 18:45:36 +0000 (11:45 -0700)
Current ATF uses a direct physical-to-virtual mapping, that is, a physical
address is mapped to the same address in the virtual space. For example,
physical address 0x8000_0000 is mapped to 0x8000_0000 virtual. This
approach works fine for FVP as all its physical addresses fall into 0 to
4GB range. But for other platform where all I/O addresses are 48-bit long,
If we follow the same direct mapping, we would need virtual address range
from 0 to 0x8fff_ffff_ffff, which is about 144TB. This requires a
significant amount of memory for MMU tables and it is not necessary to use
that much virtual space in ATF.

The patch is to enable mapping a physical address range to an arbitrary
virtual address range (instead of flat mapping)
Changed "base" to "base_va" and added "base_pa" in mmap_region_t and
modified functions such as mmap_add_region and init_xlation_table etc.
Fixes ARM-software/tf-issues#158

include/lib/aarch64/xlat_tables.h
lib/aarch64/xlat_tables.c
plat/fvp/aarch64/fvp_common.c

index 5df655bd50c01f21f5a1b6696f3ae16b63e77fd9..8e0adc7fa6298e74afd249a4da77d97e8f66b815 100644 (file)
@@ -55,13 +55,14 @@ typedef enum  {
  * Structure for specifying a single region of memory.
  */
 typedef struct mmap_region {
-       unsigned long   base;
+       unsigned long   base_pa;
+       unsigned long   base_va;
        unsigned long   size;
        mmap_attr_t     attr;
 } mmap_region_t;
 
-void mmap_add_region(unsigned long base, unsigned long size,
-                       unsigned attr);
+void mmap_add_region(unsigned long base_pa, unsigned long base_va,
+                               unsigned long size, unsigned attr);
 void mmap_add(const mmap_region_t *mm);
 
 void init_xlat_tables(void);
index 29b81dbd3c37ca455cbcc0da8bd53e57ba7fd173..1b99cc85feba3ed2f8446886cbb2d8ab6e8b0a47 100644 (file)
@@ -72,26 +72,29 @@ static void print_mmap(void)
        debug_print("mmap:\n");
        mmap_region_t *mm = mmap;
        while (mm->size) {
-               debug_print(" %010lx %10lx %x\n", mm->base, mm->size, mm->attr);
+               debug_print(" %010lx %010lx %10lx %x\n", mm->base_va,
+                                       mm->base_pa, mm->size, mm->attr);
                ++mm;
        };
        debug_print("\n");
 #endif
 }
 
-void mmap_add_region(unsigned long base, unsigned long size, unsigned attr)
+void mmap_add_region(unsigned long base_pa, unsigned long base_va,
+                       unsigned long size, unsigned attr)
 {
        mmap_region_t *mm = mmap;
        mmap_region_t *mm_last = mm + sizeof(mmap) / sizeof(mmap[0]) - 1;
 
-       assert(IS_PAGE_ALIGNED(base));
+       assert(IS_PAGE_ALIGNED(base_pa));
+       assert(IS_PAGE_ALIGNED(base_va));
        assert(IS_PAGE_ALIGNED(size));
 
        if (!size)
                return;
 
        /* Find correct place in mmap to insert new region */
-       while (mm->base < base && mm->size)
+       while (mm->base_va < base_va && mm->size)
                ++mm;
 
        /* Make room for new region by moving other regions up by one place */
@@ -100,7 +103,8 @@ void mmap_add_region(unsigned long base, unsigned long size, unsigned attr)
        /* Check we haven't lost the empty sentinal from the end of the array */
        assert(mm_last->size == 0);
 
-       mm->base = base;
+       mm->base_pa = base_pa;
+       mm->base_va = base_va;
        mm->size = size;
        mm->attr = attr;
 }
@@ -108,15 +112,15 @@ void mmap_add_region(unsigned long base, unsigned long size, unsigned attr)
 void mmap_add(const mmap_region_t *mm)
 {
        while (mm->size) {
-               mmap_add_region(mm->base, mm->size, mm->attr);
+               mmap_add_region(mm->base_pa, mm->base_va, mm->size, mm->attr);
                ++mm;
        }
 }
 
-static unsigned long mmap_desc(unsigned attr, unsigned long addr,
+static unsigned long mmap_desc(unsigned attr, unsigned long addr_pa,
                                        unsigned level)
 {
-       unsigned long desc = addr;
+       unsigned long desc = addr_pa;
 
        desc |= level == 3 ? TABLE_DESC : BLOCK_DESC;
 
@@ -142,7 +146,7 @@ static unsigned long mmap_desc(unsigned attr, unsigned long addr,
        return desc;
 }
 
-static int mmap_region_attr(mmap_region_t *mm, unsigned long base,
+static int mmap_region_attr(mmap_region_t *mm, unsigned long base_va,
                                        unsigned long size)
 {
        int attr = mm->attr;
@@ -153,10 +157,10 @@ static int mmap_region_attr(mmap_region_t *mm, unsigned long base,
                if (!mm->size)
                        return attr; /* Reached end of list */
 
-               if (mm->base >= base + size)
+               if (mm->base_va >= base_va + size)
                        return attr; /* Next region is after area so end */
 
-               if (mm->base + mm->size <= base)
+               if (mm->base_va + mm->size <= base_va)
                        continue; /* Next region has already been overtaken */
 
                if ((mm->attr & attr) == attr)
@@ -164,12 +168,14 @@ static int mmap_region_attr(mmap_region_t *mm, unsigned long base,
 
                attr &= mm->attr;
 
-               if (mm->base > base || mm->base + mm->size < base + size)
+               if (mm->base_va > base_va ||
+                       mm->base_va + mm->size < base_va + size)
                        return -1; /* Region doesn't fully cover our area */
        }
 }
 
-static mmap_region_t *init_xlation_table(mmap_region_t *mm, unsigned long base,
+static mmap_region_t *init_xlation_table(mmap_region_t *mm,
+                                       unsigned long base_va,
                                        unsigned long *table, unsigned level)
 {
        unsigned level_size_shift = L1_XLAT_ADDRESS_SHIFT - (level - 1) *
@@ -184,23 +190,26 @@ static mmap_region_t *init_xlation_table(mmap_region_t *mm, unsigned long base,
        do  {
                unsigned long desc = UNSET_DESC;
 
-               if (mm->base + mm->size <= base) {
+               if (mm->base_va + mm->size <= base_va) {
                        /* Area now after the region so skip it */
                        ++mm;
                        continue;
                }
 
-               debug_print("      %010lx %8lx " + 6 - 2 * level, base, level_size);
+               debug_print("      %010lx %8lx " + 6 - 2 * level, base_va,
+                               level_size);
 
-               if (mm->base >= base + level_size) {
+               if (mm->base_va >= base_va + level_size) {
                        /* Next region is after area so nothing to map yet */
                        desc = INVALID_DESC;
-               } else if (mm->base <= base &&
-                               mm->base + mm->size >= base + level_size) {
+               } else if (mm->base_va <= base_va && mm->base_va + mm->size >=
+                               base_va + level_size) {
                        /* Next region covers all of area */
-                       int attr = mmap_region_attr(mm, base, level_size);
+                       int attr = mmap_region_attr(mm, base_va, level_size);
                        if (attr >= 0)
-                               desc = mmap_desc(attr, base, level);
+                               desc = mmap_desc(attr,
+                                       base_va - mm->base_va + mm->base_pa,
+                                       level);
                }
                /* else Next region only partially covers area, so need */
 
@@ -211,14 +220,15 @@ static mmap_region_t *init_xlation_table(mmap_region_t *mm, unsigned long base,
                        desc = TABLE_DESC | (unsigned long)new_table;
 
                        /* Recurse to fill in new table */
-                       mm = init_xlation_table(mm, base, new_table, level+1);
+                       mm = init_xlation_table(mm, base_va,
+                                               new_table, level+1);
                }
 
                debug_print("\n");
 
                *table++ = desc;
-               base += level_size;
-       } while (mm->size && (base & level_index_mask));
+               base_va += level_size;
+       } while (mm->size && (base_va & level_index_mask));
 
        return mm;
 }
index 3a078448c6dc1f24f7126112834ba9009b4fe530..41234cba6f3c455ec21ef400ce397c7f8776c3d0 100644 (file)
@@ -54,17 +54,27 @@ static unsigned long fvp_config[CONFIG_LIMIT];
  * configure_mmu_elx() will give the available subset of that,
  */
 const mmap_region_t fvp_mmap[] = {
-       { TZROM_BASE,   TZROM_SIZE,     MT_MEMORY | MT_RO | MT_SECURE },
-       { TZDRAM_BASE,  TZDRAM_SIZE,    MT_MEMORY | MT_RW | MT_SECURE },
-       { FLASH0_BASE,  FLASH0_SIZE,    MT_MEMORY | MT_RO | MT_SECURE },
-       { FLASH1_BASE,  FLASH1_SIZE,    MT_MEMORY | MT_RO | MT_SECURE },
-       { VRAM_BASE,    VRAM_SIZE,      MT_MEMORY | MT_RW | MT_SECURE },
-       { DEVICE0_BASE, DEVICE0_SIZE,   MT_DEVICE | MT_RW | MT_SECURE },
-       { NSRAM_BASE,   NSRAM_SIZE,     MT_MEMORY | MT_RW | MT_NS },
-       { DEVICE1_BASE, DEVICE1_SIZE,   MT_DEVICE | MT_RW | MT_SECURE },
+       { TZROM_BASE,   TZROM_BASE,     TZROM_SIZE,
+                                               MT_MEMORY | MT_RO | MT_SECURE },
+       { TZDRAM_BASE,  TZDRAM_BASE,    TZDRAM_SIZE,
+                                               MT_MEMORY | MT_RW | MT_SECURE },
+       { FLASH0_BASE,  FLASH0_BASE,    FLASH0_SIZE,
+                                               MT_MEMORY | MT_RO | MT_SECURE },
+       { FLASH1_BASE,  FLASH1_BASE,    FLASH1_SIZE,
+                                               MT_MEMORY | MT_RO | MT_SECURE },
+       { VRAM_BASE,    VRAM_BASE,      VRAM_SIZE,
+                                               MT_MEMORY | MT_RW | MT_SECURE },
+       { DEVICE0_BASE, DEVICE0_BASE,   DEVICE0_SIZE,
+                                               MT_DEVICE | MT_RW | MT_SECURE },
+       { NSRAM_BASE,   NSRAM_BASE,     NSRAM_SIZE,
+                                               MT_MEMORY | MT_RW | MT_NS },
+       { DEVICE1_BASE, DEVICE1_BASE,   DEVICE1_SIZE,
+                                               MT_DEVICE | MT_RW | MT_SECURE },
        /* 2nd GB as device for now...*/
-       { 0x40000000,   0x40000000,     MT_DEVICE | MT_RW | MT_SECURE },
-       { DRAM1_BASE,   DRAM1_SIZE,     MT_MEMORY | MT_RW | MT_NS },
+       { 0x40000000,   0x40000000,     0x40000000,
+                                               MT_DEVICE | MT_RW | MT_SECURE },
+       { DRAM1_BASE,   DRAM1_BASE,     DRAM1_SIZE,
+                                               MT_MEMORY | MT_RW | MT_NS },
        {0}
 };
 
@@ -73,19 +83,21 @@ const mmap_region_t fvp_mmap[] = {
  * the platform memory map & initialize the mmu, for the given exception level
  ******************************************************************************/
 #define DEFINE_CONFIGURE_MMU_EL(_el)                                   \
-       void fvp_configure_mmu_el##_el(unsigned long total_base,                \
+       void fvp_configure_mmu_el##_el(unsigned long total_base,        \
                                   unsigned long total_size,            \
                                   unsigned long ro_start,              \
                                   unsigned long ro_limit,              \
                                   unsigned long coh_start,             \
                                   unsigned long coh_limit)             \
        {                                                               \
-               mmap_add_region(total_base,                             \
+               mmap_add_region(total_base, total_base,                 \
                                total_size,                             \
                                MT_MEMORY | MT_RW | MT_SECURE);         \
-               mmap_add_region(ro_start, ro_limit - ro_start,          \
+               mmap_add_region(ro_start, ro_start,                     \
+                               ro_limit - ro_start,                    \
                                MT_MEMORY | MT_RO | MT_SECURE);         \
-               mmap_add_region(coh_start, coh_limit - coh_start,       \
+               mmap_add_region(coh_start, coh_start,                   \
+                               coh_limit - coh_start,                  \
                                MT_DEVICE | MT_RW | MT_SECURE);         \
                mmap_add(fvp_mmap);                                     \
                init_xlat_tables();                                     \